pub mod field;
pub mod index;
pub mod query;
pub mod relation;
/// 相关工具
pub mod tools;
/// 各数据验证类型定义
pub mod types;

use crate::err::OrmError;
use crate::model::query::expr::QueryExprRightValue;
use crate::model::relation::JoinInfo;

use self::field::Field;
use self::index::Index;
use self::query::expr::QueryExpr;
use self::query::QueryBuilder;
use self::relation::JoinBaseTableInfo;
use super::err::OrmResult;

/// 最大支持10个外键
pub trait Model {
    /// 表定义信息
    const META: Meta;
    /// 表主键字段类型
    type PkType;
    /// 外键模型1
    type FkModel1: Model;
    /// 外键模型2
    type FkModel2: Model;
    /// 外键模型3
    type FkModel3: Model;
    /// 外键模型4
    type FkModel4: Model;
    /// 外键模型5
    type FkModel5: Model;
    /// 外键模型6
    type FkModel6: Model;
    /// 外键模型7
    type FkModel7: Model;
    /// 外键模型8
    type FkModel8: Model;
    /// 外键模型9
    type FkModel9: Model;
    /// 外键模型10
    type FkModel10: Model;

    /// 解析join表达式
    ///
    /// # 参数说明
    ///
    /// * cur_table_name 当前表名称
    /// * field_index 当前字段序号
    /// * is_left_join:是否left join
    /// * join_query 子表的join连接查询
    fn db_parse_join_item<'a>(
        cur_table_name: &str,
        field_index: u8,
        is_left_join: bool,
        join_query: &'a QueryExpr<'a>,
    ) -> OrmResult<QueryBuilder<'a>> {
        let field = &Self::META.field_list[field_index as usize];
        let join_base_info = JoinBaseTableInfo {
            table_org_name: Self::META.table_name,
            table_name: &cur_table_name,
            link_field_name: &field.table_field_name,
            is_left_join,
        };
        // 读取字表信息
        if let Some(fk_model_no) = &field.fk_model_no {
            // 解析join字表query
            match fk_model_no {
                field::FkNo::One => Self::FkModel1::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Two => Self::FkModel2::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Three => Self::FkModel3::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Four => Self::FkModel4::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Five => Self::FkModel5::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Six => Self::FkModel6::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Seven => Self::FkModel7::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Eight => Self::FkModel8::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Night => Self::FkModel9::db_parse(join_query, &Some(join_base_info)),
                field::FkNo::Ten => Self::FkModel10::db_parse(join_query, &Some(join_base_info)),
            }
        } else {
            Err(OrmError::NotJoinField(format!(
                "{cur_table_name}(原始表:{}).{}字段未关联其他表,无join信息",
                Self::META.table_name,
                field.name
            )))
        }
    }

    fn db_parse<'a>(
        expr: &'a QueryExpr,
        join_base_table_info: &Option<JoinBaseTableInfo>,
    ) -> OrmResult<QueryBuilder<'a>> {
        let mut wheres: Vec<String> = Vec::new();
        let mut joins: Vec<JoinInfo> = Vec::new();
        let mut selects: Vec<String> = Vec::new();
        // 用于存放where的查询值
        let mut values: Vec<&QueryExprRightValue> = Vec::new();

        // 当前解析的表名称
        let cur_table_name: String = if let Some(join_base_table_info) = &join_base_table_info {
            // 将当前表添加进join记录中
            // 生成join语句,其中join表重命名为外键字段名称_外键表名称

            // 当前表为上级表的join表，在表名称前添加上级表对应外键的名称_
            let joined_table_name = format!(
                "{}_{}_{}",
                join_base_table_info.table_name,
                join_base_table_info.link_field_name,
                Self::META.table_name
            );
            let join_pk = Self::META.get_pk().ok_or(OrmError::MissPkTable(format!(
                "join表{}无主键",
                Self::META.table_name
            )))?;

            let join_sql = format!(
                "JOIN {} AS {} ON {}.{} = {}.{}",
                Self::META.table_name,
                joined_table_name,
                join_base_table_info.table_name,
                join_base_table_info.link_field_name,
                joined_table_name,
                join_pk.table_field_name
            );

            let join_info = JoinInfo {
                join_table_meta: Self::META,
                join_table_name: joined_table_name.clone(),
                join_sql,
                base_table_org_name: join_base_table_info.table_org_name.into(),
                base_table_name: join_base_table_info.table_name.into(),
                base_table_link_field_name: join_base_table_info.link_field_name.into(),
            };
            joins.push(join_info);
            joined_table_name
        } else {
            Self::META.table_name.into()
        };

        match expr {
            QueryExpr::And { left, right } => {
                let QueryBuilder {
                    wheres: left_wheres,
                    joins: left_joins,
                    select_fields: left_selects,
                    values: left_values,
                    ..
                } = Self::db_parse(&*left, join_base_table_info)?;
                let QueryBuilder {
                    wheres: right_wheres,
                    joins: right_joins,
                    select_fields: right_selects,
                    values: right_values,
                    ..
                } = Self::db_parse(&*right, join_base_table_info)?;
                let sql = format!(
                    "( {} AND {} )",
                    left_wheres.join("\n"),
                    right_wheres.join("\n")
                );
                wheres.push(sql);
                joins.extend(left_joins);
                joins.extend(right_joins);
                selects.extend(left_selects);
                selects.extend(right_selects);
                values.extend(left_values);
                values.extend(right_values);
            }
            QueryExpr::Or { left, right } => {
                let QueryBuilder {
                    wheres: left_wheres,
                    joins: left_joins,
                    select_fields: left_selects,
                    values: left_values,
                    ..
                } = Self::db_parse(&*left, join_base_table_info)?;
                let QueryBuilder {
                    wheres: right_wheres,
                    joins: right_joins,
                    select_fields: right_selects,
                    values: right_values,
                    ..
                } = Self::db_parse(&*right, join_base_table_info)?;
                let sql = format!(
                    "( {} OR {} )",
                    left_wheres.join("\n"),
                    right_wheres.join("\n")
                );
                wheres.push(sql);
                joins.extend(left_joins);
                joins.extend(right_joins);
                selects.extend(left_selects);
                selects.extend(right_selects);
                values.extend(left_values);
                values.extend(right_values);
            }
            QueryExpr::Item {
                field_index,
                right,
                method,
            } => {
                let field = &Self::META.field_list[*field_index as usize];
                let field_sql = format!("{}.{}", cur_table_name, field.name);
                let sql = method.to_sql_for_value(field, &field_sql, &right)?;
                wheres.push(sql);
                values.push(&right);
            }
            QueryExpr::Not { query } => {
                todo!()
            }
            QueryExpr::Join {
                field_index,
                is_left_join,
                join_query,
            } => {
                let QueryBuilder {
                    wheres: join_where,
                    joins: join_joins,
                    select_fields: join_selects,
                    values: join_values,
                    ..
                } = Self::db_parse_join_item(
                    &cur_table_name,
                    *field_index,
                    *is_left_join,
                    &*join_query,
                )?;

                wheres.extend(join_where);
                joins.extend(join_joins);
                selects.extend(join_selects);
                values.extend(join_values);
                //todo!("怎么合并到子表中,核实join的sql合并是否正确")
            }
        }
        // 去除重复的join
        joins.sort_by(|a, b| a.join_table_name.cmp(&b.join_table_name));
        joins.dedup_by(|a, b| a.join_table_name.eq(&b.join_table_name));

        Ok(QueryBuilder {
            base_meta: Self::META,
            select_fields: selects,
            wheres,
            joins,
            values,
        })
    }
    /// 获取多个
    fn db_filter(expr: QueryExpr) -> OrmResult<QueryBuilder> {
        let builder = Self::db_parse(&expr, &None)?;
        let sql = builder.get_select_sql(true);
        println!("{builder:#?} \n {sql}");
        todo!()
    }
    /// 获取1个
    fn db_get() {
        unimplemented!()
    }
    /// 保存到数据库
    fn db_save() {
        unimplemented!()
    }
    /// 从数据库删除
    fn db_delete() {
        unimplemented!()
    }
}

/// 表元数据
#[derive(Debug)]
pub struct Meta {
    /// 对应数据库表名称
    pub table_name: &'static str,
    /// 表字段清单
    pub field_list: &'static [Field],
    /// 索引清单
    pub index_list: Option<&'static [Index]>,
}
impl Meta {
    /// 通过字段名称获取对应字段信息
    ///
    /// * name 要获取的字段名称，必须与struct定义完全一致
    pub fn get_field(&self, name: &str) -> Option<&Field> {
        self.field_list.iter().find(|field| field.name == name)
    }
    /// 获取主键
    pub fn get_pk(&self) -> Option<&Field> {
        self.field_list.iter().find(|field| field.pk)
    }
}

/// 无外键时使用()作为外键类型
impl Model for () {
    const META: Meta = Meta {
        table_name: "",
        field_list: &[],
        index_list: None,
    };

    type PkType = ();

    type FkModel1 = Self;

    type FkModel2 = Self;

    type FkModel3 = Self;

    type FkModel4 = Self;

    type FkModel5 = Self;

    type FkModel6 = Self;

    type FkModel7 = Self;

    type FkModel8 = Self;

    type FkModel9 = Self;

    type FkModel10 = Self;
}
